#include "CRectangle.h"

bool CRectangle::legalWidthHeight ( int width, int height) const
{
	if (width < 0 || height < 0)
	{
		cerr << "Error: width and height must have positive value" << endl;
		return false;
	}

	return true;
}

bool CRectangle::isInBorders () const
{
	int x1, y1, maxWidth, maxHeight;

	x1 = (int)(m_sumDirX + m_point.getx());
	y1 = (int)(m_sumDirY + m_point.gety());
	maxWidth = m_width + x1;
	maxHeight = m_height + y1;

	if (x1 < MIN_SCREEN_X ||
		y1 < MIN_SCREEN_Y ||
		maxWidth >= MAX_SCREEN_X ||
		maxHeight >= MAX_SCREEN_Y )
		return false;
	return true;
}

void CRectangle::set(Point p1, int width, int height)
{	
	Shape::set (p1, 0, 0);

	m_width = width;
	m_height = height;

}

bool CRectangle::input()
{
	Point p1;
	int width, height;

	p1.input();

	cout << "Please enter the width of the rectangle: ";
	cin >> width;
	cout << "Please enter the height of the rectangle: ";
	cin >> height;

	if (legalWidthHeight(width, height))
	{
		this->set (p1, width, height);
		return true;
	}
	
	return false;
}

bool CRectangle::draw( char frameCh, bool fill, MyScreen * scr, 
					bool split) 
{
	int x, y, maxHeight, maxWidth;
	Point printedPoint;

	x = m_point.getx();
	y = m_point.gety();

	// Adds to that value the movment axis (if there is no movment, the sumDir = 0)
	x += (int)m_sumDirX;
	y += (int)m_sumDirY;

	if (split)
	{
		// for the modulu to work, the X and Y values should be bigger than the screen minimum (0)
		if ((x+1) < MIN_SCREEN_X)
		{
				// for the next itteration - let the sum (that is added to the x value) be 1 screen bigger
				m_sumDirX += (m_sumDirX < MIN_SCREEN_X ? (MAX_SCREEN_X-1) : 0); 
				x += (MAX_SCREEN_X-1);
		}

		if ((y+1) < MIN_SCREEN_Y)
		{
				m_sumDirY += (m_sumDirY < MIN_SCREEN_Y ? (MAX_SCREEN_Y-1) : 0); 
				y += (MAX_SCREEN_Y-1);
		}
	}

	maxWidth = x + m_width -1;
	maxHeight = y + m_height -1;

	if (fill)
	{
		for ( int i=1; i < (m_width-1); ++i)
			for ( int j=1; j < (m_height-1); ++j)
			{
				printedPoint.set(x+i, y+j);
				splitPoint (printedPoint, split);
				Point::printPoint (printedPoint, scr, ' ');
			}
	}

	for ( int i=0; i < m_height; ++i)
	{
		printedPoint.set(x, y+i);
		splitPoint (printedPoint, split);
		Point::printPoint (printedPoint, scr, frameCh);

		printedPoint.set(maxWidth, y+i);
		splitPoint (printedPoint, split);
		Point::printPoint (printedPoint, scr, frameCh);
	}

	for ( int i=0; i < m_width; ++i)
	{
		printedPoint.set(x+i, y);
		splitPoint (printedPoint, split);
		Point::printPoint (printedPoint, scr, frameCh);

		printedPoint.set(x+i, maxHeight);
		splitPoint (printedPoint, split);
		Point::printPoint (printedPoint, scr, frameCh);
	}

	return true;
}

void CRectangle::splitPoint (Point& splitPoint, bool split)
{
	int modFactorX = MAX_SCREEN_X-1, modFactorY = MAX_SCREEN_Y-1;

	// the split of the screen action
	if (split)
	{
		int x = splitPoint.getx() % modFactorX;
		int y = splitPoint.gety() % modFactorY;
		splitPoint.set (splitPoint.getx() % modFactorX, splitPoint.gety() % modFactorY);
	}

	return;
}

bool CRectangle::search(const Point& p1) const
{

	int x = m_point.getx();
	int maxWidth = m_width + x - 1;

	int y = m_point.gety();
	int maxHeight = m_height + y - 1;

	int p1X = p1.getx();
	int p1Y = p1.gety();

	if (p1X >= x && p1X <= maxWidth && p1Y >= y && p1Y <= maxHeight)
		return true;

	return false;
}

void CRectangle::handleCollision (CRectangle * rec)
{
	HandleCollisions::handleRectangleRectangleCollision (this, rec);
	return;
}

void CRectangle::handleCollision (Circle * circ)
{
	HandleCollisions::handleRectangleCircleCollision (this, circ);
	return;
}

void CRectangle::handleCollision (Shape * shape)
{
	(shape)->handleCollision(this);
	return;
}

bool CRectangle::checkStuck (const MyScreen & scr) const
{
	return HandleCollisions::checkRecStuck(*this , scr);
}

bool CRectangle::writeToText(ofstream & file) 
{
	Shape::writeToText(file);
	file << this->getHeight() << " ";
	file << this->getWidth() << " ";

	return true;

}